/*
 * @Author      : ZhouQiJun
 * @Date        : 2025-08-07 00:32:22
 * @LastEditors : ZhouQiJun
 * @LastEditTime: 2025-08-07 01:33:30
 * @Description : 对象属性转换工具
 */
import type { Many } from '@ol/types'
import { isString } from 'es-toolkit'
import { get, set } from 'es-toolkit/compat'

type PropertyPath = Many<PropertyKey>

type Field<V = unknown> =
  | {
      field: string
      alias?: PropertyPath
      value?: V
    }
  | string

/**
 * 将对象的属性按照指定字段配置进行转换或映射
 *
 * @template T - 源对象的类型，必须是键为字符串的记录类型
 * @template V - 字段值的类型，默认为 unknown
 *
 * @param {T} target - 要处理的目标对象
 * @param {'*' | string | Field<V>[]} fields - 字段配置，可以是：
 *   - '*' 表示选择所有属性
 *   - 字符串表示单个字段名
 *   - Field 数组表示多个字段配置
 *
 * @returns {Record<string, unknown>} - 返回处理后的对象：
 *   - 如果 fields 为 '*' 则返回原对象
 *   - 如果是字段配置则返回新对象，包含指定的字段
 *     - 对于简单字符串字段，直接复制属性值
 *     - 对于带别名的配置，会将值设置到别名路径下
 *     - 如果配置了 value 则使用该值，否则使用原对象的值
 *
 * @example
 * // 返回 { name: 'John', age: 30 }
 * toProperties({ name: 'John', age: 30, id: 1 }, ['name', 'age'])
 *
 * @example
 * // 返回 { userName: 'John', userAge: 30 }
 * toProperties({ name: 'John', age: 30 }, [
 *   { field: 'name', alias: 'userName' },
 *   { field: 'age', alias: 'userAge' }
 * ])
 *
 * @example
 * // 返回 { name: 'John', info: { age: 30 } }
 * toProperties({ name: 'John', age: 30 }, [
 *   'name',
 *   { field: 'age', alias: ['info', 'age'] }
 * ])
 */
export default function toProperties<T extends Record<string, unknown>, V = unknown>(
  target: T,
  fields: '*' | string | Field<V>[],
): Record<string, unknown> {
  if (fields === '*') return target

  let _fields = fields as Field[]
  if (isString(fields)) _fields = [fields]
  const initObj = {} as Record<string, unknown>

  return _fields?.reduce(convertObj, initObj)

  function convertObj(acc: Record<string, unknown>, v: string | Field) {
    if (typeof v === 'string') {
      acc[v] = get(target, v)
    } else if (v.alias) {
      // 设置别名
      set(acc, v.alias, v.value ?? get(target, v.field))
    } else {
      acc[v.field] = v.value ?? get(target, v.field)
    }
    return acc
  }
}
